iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0
Modern Web

Phoenix 1.7 完全教學系列 第 27

27 LiveComponent 表格 2

  • 分享至 

  • xImage
  •  

顯示表格

建立 lib/gratitude_web/live/note_live/form_component.ex 並填入:

defmodule GratitudeWeb.NoteLive.FormComponent do
  use GratitudeWeb, :live_component
  alias Gratitude.Notes
  alias Gratitude.Notes.Note

  def update(_params, socket) do
    form =
      %Note{}
      |> Note.changeset(%{})
      |> to_form()

    {:ok, assign(socket, form: form)}
  end

  def render(assigns) do
    ~H"""
    <div>
      <.header>
        新增感激筆記
      </.header>

      <.simple_form for={@form} phx-target={@myself} phx-change="validate" phx-submit="save">
        <.input field={@form[:content]} type="text" label="內容" />
        <:actions>
          <.button>送出</.button>
        </:actions>
      </.simple_form>
    </div>
    """
  end
end

update 開始,這裡與先前在 Controller-View 的步驟很像,先產生一個新增 note 的 changeset,再放到 assigns 裡面提供給表格,不過在 LiveView 這邊推薦先使用 to_form 轉換成對 LiveView 更新畫面更有效率的 Phoenix.HTML.Form struct。

一樣是由 CoreComponent 提供的.simple_form component 裡面用的一樣是 <.form> 使用方式一樣,只是多了造型與 <:action> slot 提供擺放按鈕的位置。

要注意的是,在 LiveView 中,<.form> 上使用 phx-change 來即時檢查表單的輸入,phx-submit 來處理表單送出的事件。
這兩個都是使用 handle_event 來接收。

(由於是要發給 component 自己,form 上面必須要加入 phx-target={@myself},否則事件會發到父層的 LiveView)

檢查

在 LiveView 預設每次表單有改變,就會發出 phx-change 事件給 LiveView,所以我們只要在 handle_event 裡面接收即可。

def handle_event("validate", %{"note" => note_params}, socket) do
  form =
    %Note{}
    |> Note.changeset(note_params)
    |> Map.put(:action, :validate)
    |> to_form()

  {:noreply, assign(socket, form: form)}
end

當我們使用 handle_event 接收相對應的事件時(這裡是 "validate" ),可以在 params 內得到表單目前的內容,在這邊把 params 傳到 changeset 裡面,並且把 action 設為 :validate<.form> 就會顯示目前的表格的錯誤欄位與原因。

儲存

如果按下送出按鈕,就會發出 phx-submit 事件,我們可以實作另一個 handle_event 來接收這個事件,並且在這裡處理儲存的邏輯。

與在 Controller-View 裡的 create 函式一樣,使用我們在 context 寫好的 Notes.create_note 錯誤的話,就把錯誤的 changeset 傳回表單,讓使用者可以修改,成功的話有幾件事要處理:

  1. 使用 put_flash 來顯示成功的訊息
  2. 使用 push_patch 回到 /:index live_action,這會關閉目前的表格(在上一篇有設定 live_action 是 :new 的話才開啟表格)
  3. 儘管 2 會關閉新增的 modal,但一樣不會更新目前的列表,所以我們要使用 send 來發送訊息給 LiveView,讓它更新列表。
def handle_event("save", %{"note" => note_params}, socket) do
  case Notes.create_note(note_params) do
    {:ok, _note} ->
      send(self(), :saved)

      {:noreply,
        socket
        |> put_flash(:info, "新增成功")
        |> push_patch(to: ~p"/")}

    {:error, changeset} ->
      {:noreply, assign(socket, form: to_form(changeset))}
  end
end

更新列表

回到 lib/gratitude_web/live/note_live/index.ex 加入新的 handle_info 來接收 {:saved, note} 訊息,並重新讀取新的列表。

def handle_info(:saved, socket) do
  {:noreply, socket |> assign(:notes, Notes.list_notes())}
end

更新了 assigns 裡的 notes 之後畫面會自動更新

使用 FormComponent

最後在 <.modal> 裡替換成剛剛建立的 FormComponent 。

<.modal :if={@live_action in [:new, :edit]} id="book-modal" show on_cancel={JS.patch(~p"/")}>
  <.live_component
    module={GratitudeWeb.NoteLive.FormComponent}
    id="new_note_form"
    action={@live_action}
  />
</.modal>

https://i.imgur.com/BrqL74a.gif


上一篇
26 Live Component 表格 1
下一篇
28 LiveView 測試
系列文
Phoenix 1.7 完全教學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言